from datetime import datetime

from django.shortcuts import render
import  json
# Create your views here.
from django.shortcuts import render
from django.views import View
from django_redis import get_redis_connection

from meiduo_mall.utils.breadcrumb import get_breadcrumb
from meiduo_mall.utils.meiduo_category import get_categories
from .models import GoodsCategory, SKU, GoodsVisitCount
from django.core.paginator import Paginator
from . import constants
from django import http
from meiduo_mall.utils.response_code import RETCODE

class ListView(View):
    def get(self, request, category_id, page_num):
        # 查询第三级分类对象,当点击页面手机三级分类的时候，会发送三级分类的请求，category
        #_id 作为参数传到服务器被接受查询三级分类的数据，，，获得三级分类的对象
        try:
            category3 = GoodsCategory.objects.get(pk=category_id)
        except:
            return render(request, '404.html')

        # - 分类数据.调用分类数据
        categories = get_categories()

        # - 面包屑导航,反推由三级分类可以反推到一级分类
        # 作为外键关联，关联的表中隐含一个字段　是另外一个表类的小写加set，
        # 在查询所有频道的时候，[0].url表示每一个频道中的路径信息
        category2 = category3.parent
        category1 = category2.parent
        breadcrumb = {
            'cat1': {
                'name': category1.name,
                'url': category1.goodschannel_set.all()[0].url
            },
            'cat2': category2,
            'cat3': category3
        }

        # - 热销排行(使用ajax查询)

        # - 当前分类数据  ｃａｔｅｇｒｏｙ３在商品分类表中，且sku与之外键关联，多对一
        #所以在商品分类中　ｓｋｕ_set　获取sku中所有商品信息属性
        skus = category3.sku_set.filter(is_launched=True) #商品信息是否上架

        # - 排序，默认排序的情况下以新上架的商品　－price　表示递减。从大到小的顺序进行排序
        sort = request.GET.get('sort', 'default')
        if sort == 'hot':  # 人气hot
            skus = skus.order_by('-sales')
        elif sort == 'price':  # 价格price
            skus = skus.order_by('price')
        else:  # 默认default
            skus = skus.order_by('-id')

        # - 分页
        # 创建分页对象，导入一个分页的类，
        paginator = Paginator(skus, constants.LIST_PER_PAGE)
        # 获取指定页的数据
        page_skus = paginator.page(page_num)

        context = {
            'categories': categories,
            'breadcrumb': breadcrumb,
            'page_skus': page_skus,
            'category': category3,
            'sort': sort,
            'page_num': page_num,
            'total_page': paginator.num_pages
        }
        return render(request, 'list.html', context)


class HotView(View):
    def get(self, request, category_id):
        # 查询2个最热销的商品,切片操作　[(),(),()]  >>>[0:2]  取下表为０－１
        skus = SKU.objects.filter(is_launched=True, category_id=category_id).order_by('-sales')[0:2]

        # 格式转换成Json，ａｊax请求渲染页面
        sku_list = []
        for sku in skus:
            sku_list.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price
            })

        # 响应
        return http.JsonResponse({
            'code': RETCODE.OK,
            'errmsg': 'ok',
            'hot_sku_list': sku_list
        })

#实际１，首先查询的是三级分类，建立一个三级分类的对象，
# ２．通过面包屑导航，反推一级二级，根据前端页面的需求，添加需要的数据
#数据的排序　，默认，人气，价格　　－－－创建商品的分页，导入一个类，创建类的方法，通过方法实现分页的操作，在模板渲染的时候需要传递一些参数
# 前端通过路劲的方式传来一个页面的参数，
# 查询两个热销的商品，按照人气排序，[()()()]>>>>>[{}{}{}]  遍历转化成ＪＳＯＮ的形式输出
#
# ----------------
#建立商品详细页面的视图

class DetailView(View):
    def get(self, request, sku_id):
        try:
            sku = SKU.objects.get(pk=sku_id)
        except:
            return render(request, '404.html')
        # 三级分类
        category3 = sku.category

        # 频道分类
        categories = get_categories()

        # 面包屑导航
        breadcrumb = get_breadcrumb(category3)

        # sku对象数据：在前面已经根据编号查询
        # 当前库存商品的规格选项信息，结果如编号为16的库存商品对应的选项为：[16,21]
        sku_options = sku.specs.order_by('spec_id')
        sku_option_list = [info.option_id for info in sku_options]
        # print(sku_option_list)　　　[8,11]　　把前端传来的ｓku_id 转化为　sku_option_list >>[颜色，规格]
        # 获取标准商品对象spu
        spu = sku.spu

        # 关联查询通过标准商品===》所有库存商品===》所有选项信息　三个表的关联查找
        skus = spu.sku_set.filter(is_launched=True)
        #过滤要上架的商品
        sku_option_dict = {}
        for sku_info in skus:
            # 遍历该对象下所有库存商品，
            sku_info_options = sku_info.specs.order_by('spec_id')  #该商品下是所有规格2
            # 查询每个库存商品对应的规格，再根据由规格拿出每个商品对应的规格选项，组成一个　[16,21]
            sku_info_option_list = [option_info.option_id for option_info in sku_info_options]
            # 将选项列表为键，库存商品编号为值
            sku_option_dict[tuple(sku_info_option_list)] = sku_info.id  #  　{[],[],[]...}规格选项绑定商品id
            # 如"[8,10]":商品id ,建立每一个规格对应商品字典{[颜色，规格]:１号商品id ,[]:２号商品id ,[]:３号商品id ．．．．}
        # sku==>spu==>规格===>选项
        specs = spu.specs.all()
        # print(specs)
        #查询当前标准商品的规格
        specs_list = []
        for index, spec in enumerate(specs):    #建立索引标记商品规格　如颜色标记为０　内存标记位１　
            # 转换规格数据
            spec_dict = {
                'name': spec.name,
                'options': []                  #输出规格的名字　和规格中包含的规格选项列表
            }
            # 查询当前商品规格的选项
            options = spec.options.all()
            # print(options)
            #查询规格选项，建立两个for循环迭代找出每一个规格下的选项
            for option in options:             #遍历选项．从每一个选项中拿出颜色，内存　和选项唯一标识
                option_dict = {
                    'name': option.value,
                    'id': option.id
                }

                # 复制当前库存商品的选项实际option.id 是当前商品规格选项表的ｉｄ　＝　规格表的option_id
                sku_option_list_temp = sku_option_list[:]#深拷贝[16,21]
                # 当前选项是否选中
                if option.id in sku_option_list:  # [16,21]
                    option_dict['selected'] = True
                else:
                    option_dict['selected'] = False
                # 为选项指定库存商品编号0 ---6---16     1------7----21
                sku_option_list_temp[index] = option.id #表示指定在规格表建立的索引[16,21] 每一个规格的选
                option_dict['sku_id'] = sku_option_dict[tuple(sku_option_list_temp)]
                #sku_option_dict[tuple(sku_option_list_temp)] 可以表示为sku_info.id 商品id

                spec_dict['options'].append(option_dict)
            # 添加规格数据
            specs_list.append(spec_dict)

        # 热销排行
        # 其它：sku===>spu


        context = {
            'categories': categories,
            'breadcrumb': breadcrumb,
            'sku': sku,
            'spu': spu,
            'category_id': category3.id,
            'specs': specs_list
        }
        return render(request, 'detail.html', context)

# 逻辑思维：

# 第一当用户点击商品规格的时候,sku_id,发生变化，＞＞规格选项发生变化．　sku>规格信息，为了得到当前商品的规格[16,21]
# 第二获取spu对象,
# 第三spu>sku>商品规格　为了得到该类商品规格列表,建立每一个规格对应商品字典{[颜色，规格]:１号商品id ,[]:２号商品id ,[]:３号商品id ．．．．}
# 第四部ｓｋｕ>spu>规格＞规格选项 找到当前商品两个for循环遍历得到某一个规格对应的一个规格选项option.id，对第一次接受前端的sku_id解析的规格[16,21]
# 第五部判断遍历的option.id是否在 sku_option_list中，在里面就标记选中，深拷贝sku_option_list，为了固定一个规格不变改变另外一个规格
# 第六部sku_option_list_temp[index] = option.id　，将改变的数据在列表中通过索引更改
# 第七option_dict['sku_id'] = sku_option_dict[tuple(sku_option_list_temp)]　,将列表更改后的数据加入到字典

# －－－－－－－－－－－－－－－－访问量－－－－－－－－－－－－－－－－－－－－
class DetailVisitView(View):
    def post(self,request,category_id):
            # 当天的访问日期
            now = datetime.now()
            date = '%d-%d-%d'%(now.year,now.month,now.day)
            #查询
            try:

                visit = GoodsVisitCount.objects.get(category_id = category_id,date=date)
            except:
                GoodsVisitCount.objects.create(category_id = category_id,count=1)
            else:
                visit.count +=1
                visit.save()
            return http.JsonResponse({
                'code': RETCODE.OK,
                'errmsg': 'ok'
            })
#保存用户的浏览记录
class HistoryView(View):
    def post(self,request):
        # 接受
        sku_id = json.loads(request.body.decode()).get('sku_id')
        # print(type(sku_id))
        # 验证
        #非空
        if not all([sku_id]):
            return  http.JsonResponse({
              'code':RETCODE.PARAMERR,
                'errmsg':'参数不齐宝贝'
            })
        #用户是否登陆
        user = request.user
        if not user.is_authenticated:
            return http.JsonResponse({'code':RETCODE.PARAMERR,
                                      'errmsg':'宝贝你还没登陆呢'
                                      })
        #判断库存商品是否有效
        try:
            sku = SKU.objects.get(pk = sku_id)#如果商品下架查询不到
        except:
            return http.JsonResponse({
                'code':RETCODE.PARAMERR,
                'errmsg':'宝贝你的商品编号数据库查无此号'

            })
        # 处理，商品编号在数据库存在，执行以下操作
        redis_cli = get_redis_connection('history')
        reids_pl = redis_cli.pipeline()  #调用pipeline来执行多任务操作
        #先去重,把原来的数据删除再从左边添加
        key = 'history%d'%user.id  #当前用户的ｉｄ
        reids_pl.lrem(key,0,sku_id)
        #添加新的数据
        reids_pl.lpush(key,sku_id)
        #限制商品浏览个数
        reids_pl.ltrim(key,0,4)
        #多任务与redis交互执行
        reids_pl.execute()
         # 响应
        return http.JsonResponse({
            'code':RETCODE.PARAMERR,
            'errmsg':'ok'

        })
    def get(self,request):
        # 判断用户是否登陆
        user = request.user
        if not user.is_authenticated:
            return http.JsonResponse({
                'code':RETCODE.PARAMERR,
                'errmsg':'宝贝，请确认你是否登陆'
            })
        #链接数据库
        redis_cli = get_redis_connection('history')
        key = 'history%d'%user.id
        sku_ids1 = redis_cli.lrange(key,0 ,-1)
        #数据库查询的数据是以bytes的形式存在
        sku_ids = [ int(sku_id) for sku_id in sku_ids1]
        #将redis转化为html的json格式
        sku_list = []
        for sku_id in sku_ids:
            sku = SKU.objects.get(pk = sku_id)
            sku_dict = {
                'name':sku.name,
                'id':sku.id,
                'default_image_url':sku.default_image.url,
                'price':sku.price
            }

            sku_list.append(sku_dict)

        return http.JsonResponse({
            'code':RETCODE.PARAMERR,
            'errmsg': 'ok',
            'skus':sku_list
        })
